🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / network / src / androidMain / kotlin / org / meshtastic / core / network / radio / SerialRadioTransport.kt
Displaying Raw • Download
core/network/src/androidMain/kotlin/org/meshtastic/core/network/radio/SerialRadioTransport.kt bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 21.85 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.network.radio
Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787com.hoho.android.usbserial.driver.UsbSerialDriver
Tff7b72import T7ee787kotlinx.coroutines.CancellationException
Tff7b72import T7ee787kotlinx.coroutines.CompletableDeferred
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.CoroutineStart
Tff7b72import T7ee787kotlinx.coroutines.Deferred
Tff7b72import T7ee787kotlinx.coroutines.Job
Tff7b72import T7ee787kotlinx.coroutines.NonCancellable
Tff7b72import T7ee787kotlinx.coroutines.SupervisorJob
Tff7b72import T7ee787kotlinx.coroutines.cancel
Tff7b72import T7ee787kotlinx.coroutines.flow.StateFlow
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787kotlinx.coroutines.withTimeoutOrNull
Tff7b72import T7ee787org.meshtastic.core.common.util.handledLaunch
Tff7b72import T7ee787org.meshtastic.core.common.util.nowMillis
Tff7b72import T7ee787org.meshtastic.core.network.repository.SerialConnection
Tff7b72import T7ee787org.meshtastic.core.network.repository.SerialConnectionListener
Tff7b72import T7ee787org.meshtastic.core.network.transport.HeartbeatSender
Tff7b72import T7ee787org.meshtastic.core.network.transport.StreamFrameCodec
Tff7b72import T7ee787org.meshtastic.core.repository.RadioTransportCallback
Tff7b72import T7ee787org.meshtastic.core.repository.TransportDisconnectReason
Tff7b72import T7ee787java.util.concurrent.atomic.AtomicBoolean
Tff7b72import T7ee787java.util.concurrent.atomic.AtomicReference
Tff7b72import T7ee787kotlin.time.Duration.Companion.seconds
T8b949e// The outer teardown can await one nested connection-gate close (15 s drain + 15 s teardown) and its connect wait.
Tff7b72private Tff7b72val Te6edf3SERIAL_TRANSPORT_TEARDOWN_TIMEOUT Tff7b72=
Te6edf3TransportLifecycleGateTb4b4b4.Te6edf3OPERATION_DRAIN_TIMEOUT Tff7b72+ Te6edf3TransportLifecycleGateTb4b4b4.Te6edf3TEARDOWN_TIMEOUT Tff7b72+ T79c0ff1T79c0ff5.Te6edf3seconds
T8b949e/** Resolves a selected serial address, retaining the legacy single-device fallback used by older installs. */
Tff7b72internal Tff7b72fun Td2a8ffresolveSerialDeviceTb4b4b4(Te6edf3devicesTb4b4b4: Te6edf3MapTff7b72<Tffa657StringTb4b4b4, Te6edf3UsbSerialDriverTff7b72>Tb4b4b4, Te6edf3addressTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Te6edf3UsbSerialDriver? Tff7b72=
Te6edf3devicesTff7b72[Te6edf3addressTff7b72] Tff7b72?: Te6edf3devicesTb4b4b4.Te6edf3valuesTb4b4b4.Te6edf3singleOrNullTb4b4b4(Tb4b4b4)
T8b949e/** An Android USB/serial [RadioTransport] implementation. */
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooManyFunctionsTa5d6ff"Tb4b4b4)
Tff7b72class T56d364SerialRadioTransportTb4b4b4(
Te6edf3callbackTb4b4b4: Te6edf3RadioTransportCallbackTb4b4b4,
Te6edf3scopeTb4b4b4: Te6edf3CoroutineScopeTb4b4b4,
Tff7b72private Tff7b72val Te6edf3serialDevicesTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3MapTff7b72<Tffa657StringTb4b4b4, Te6edf3UsbSerialDriverTff7b72>Tff7b72>Tb4b4b4,
Tff7b72private Tff7b72val Te6edf3createSerialConnectionTb4b4b4: Tb4b4b4(Te6edf3UsbSerialDriverTb4b4b4, Te6edf3SerialConnectionListenerTb4b4b4) Tff7b72-Tff7b72> Te6edf3SerialConnectionTb4b4b4,
Tff7b72private Tff7b72val Te6edf3addressTb4b4b4: Tffa657StringTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3StreamTransportTb4b4b4(Te6edf3callbackTb4b4b4, Te6edf3scopeTb4b4b4) Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3connRef Tff7b72= Te6edf3AtomicReferenceTff7b72<Te6edf3SerialConnection?Tff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3connectionAdmissionLock Tff7b72= Tffa657AnyTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72class T56d364ConnectionToken Tb4b4b4{
Tff7b72var Te6edf3connectionTb4b4b4: Te6edf3SerialConnection? Tff7b72= Tff7b72null
Tff7b72val Te6edf3lifecycle Tff7b72= Te6edf3TransportLifecycleGateTb4b4b4(Ta5d6ff"Ta5d6ffAndroid serial connectionTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3connectCompletion Tff7b72= Te6edf3CompletableDeferredTff7b72<Tffa657UnitTff7b72>Tb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72data Tff7b72class T56d364ConnectionOperationTb4b4b4(
Tff7b72val Te6edf3tokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4,
Tff7b72val Te6edf3connectionTb4b4b4: Te6edf3SerialConnectionTb4b4b4,
Tff7b72val Te6edf3leaseTb4b4b4: Te6edf3TransportLifecycleGateTb4b4b4.Te6edf3OperationLeaseTb4b4b4,
Tb4b4b4)
Tff7b72private Tff7b72data Tff7b72class T56d364ClaimedConnectionTb4b4b4(
Tff7b72val Te6edf3tokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4,
Tff7b72val Te6edf3connectionTb4b4b4: Te6edf3SerialConnectionTb4b4b4,
Tff7b72val Te6edf3cleanupCompletionTb4b4b4: Te6edf3CompletableDeferredTff7b72<Tffa657UnitTff7b72>Tb4b4b4,
Tb4b4b4)
Tff7b72private Tff7b72data Tff7b72class T56d364ConnectionStatsTb4b4b4(
Tff7b72val Te6edf3connectStartedAtTb4b4b4: Tffa657LongTb4b4b4,
Tff7b72var Te6edf3connectedAtTb4b4b4: Tffa657Long Tff7b72= T79c0ff0LTb4b4b4,
Tff7b72var Te6edf3packetsReceivedTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4,
Tff7b72var Te6edf3bytesReceivedTb4b4b4: Tffa657Long Tff7b72= T79c0ff0LTb4b4b4,
Tb4b4b4)
Tff7b72private Tff7b72var Te6edf3activeConnectionTokenTb4b4b4: Te6edf3ConnectionToken? Tff7b72= Tff7b72null
T8b949e/** Guarded by [connectionAdmissionLock]; replacement waits until old physical cleanup and notification finish. */
Tff7b72private Tff7b72var Te6edf3connectionCleanupInProgress Tff7b72= Tff7b72false
Tff7b72private Tff7b72var Te6edf3connectionCleanupCompletionTb4b4b4: Te6edf3CompletableDeferredTff7b72<Tffa657UnitTff7b72>Tff7b72? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3connectAfterCleanupScheduled Tff7b72= Tff7b72false
Tff7b72private Tff7b72val Te6edf3connectionReady Tff7b72= Te6edf3AtomicBooleanTb4b4b4(Tff7b72falseTb4b4b4)
Tff7b72private Tff7b72val Te6edf3lifecycle Tff7b72=
Te6edf3TransportLifecycleGateTb4b4b4(Ta5d6ff"Ta5d6ffAndroid serialTa5d6ff"Tb4b4b4, Te6edf3teardownTimeout Tff7b72= Te6edf3SERIAL_TRANSPORT_TEARDOWN_TIMEOUTTb4b4b4)
T8b949e// Detached from the service scope so a claimed generation always publishes cleanup completion.
Tff7b72private Tff7b72val Te6edf3cleanupScope Tff7b72= Te6edf3CoroutineScopeTb4b4b4(Te6edf3SupervisorJobTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3scopeTb4b4b4.Te6edf3coroutineContextTb4b4b4.Te6edf3minusKeyTb4b4b4(Te6edf3JobTb4b4b4)Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3heartbeatSender Tff7b72= Te6edf3HeartbeatSenderTb4b4b4(Te6edf3sendToRadio Tff7b72= Tb4b4b4{ Te6edf3handleSendToRadioTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}Tb4b4b4, Te6edf3logTag Tff7b72= Ta5d6ff"Ta5d6ffSerial[Tffd700$Te6edf3addressTa5d6ff]Ta5d6ff"Tb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffstartTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3connectTb4b4b4(Tb4b4b4)
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffcloseTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72var Te6edf3completed Tff7b72= Tff7b72false
Tff7b72try Tb4b4b4{
Te6edf3completed Tff7b72=
Te6edf3lifecycleTb4b4b4.Te6edf3closeTb4b4b4(
Te6edf3beforeDrain Tff7b72= Tb4b4b4{
T8b949e// Closing admission first suppresses a deferred disconnect while stopping this worker releases
T8b949e// its transport and connection leases.
Tff7b72superTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Te6edf3teardown Tff7b72= Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Closing serial transportTa5d6ff" Tb4b4b4}
Te6edf3closeConnectionAndAwaitConnectTb4b4b4(Te6edf3waitForStopped Tff7b72= Tff7b72trueTb4b4b4)
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3cleanupScopeTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3completedTb4b4b4) Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial teardown did not complete within its lifecycle boundsTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffonDeviceDisconnectTb4b4b4(
Te6edf3waitForStoppedTb4b4b4: Tffa657BooleanTb4b4b4,
Te6edf3isPermanentTb4b4b4: Tffa657BooleanTb4b4b4,
Te6edf3errorMessageTb4b4b4: Tffa657String?Tb4b4b4,
Te6edf3reasonTb4b4b4: Te6edf3TransportDisconnectReason?Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3disconnectConnectionTb4b4b4(
Te6edf3connectionToken Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3waitForStopped Tff7b72= Te6edf3waitForStoppedTb4b4b4,
Te6edf3isPermanent Tff7b72= Te6edf3isPermanentTb4b4b4,
Te6edf3errorMessage Tff7b72= Te6edf3errorMessageTb4b4b4,
Te6edf3reason Tff7b72= Te6edf3reasonTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffclaimConnectionTb4b4b4(Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionToken? Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4: Te6edf3ClaimedConnection? Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3token Tff7b72= Te6edf3activeConnectionToken Tff7b72?: Tff7b72returnTf0883e@synchronized Tff7b72null
Tff7b72val Te6edf3connection Tff7b72= Te6edf3connRefTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72returnTf0883e@synchronized Tff7b72null
Tff7b72if Tb4b4b4(Te6edf3connectionToken Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Tff7b72!Te6edf3ownsConnectionLockedTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3connectionTb4b4b4)Tb4b4b4) Tff7b72returnTf0883e@synchronized Tff7b72null
Te6edf3connRefTb4b4b4.Te6edf3setTb4b4b4(Tff7b72nullTb4b4b4)
Te6edf3connectionReadyTb4b4b4.Te6edf3setTb4b4b4(Tff7b72falseTb4b4b4)
Te6edf3activeConnectionToken Tff7b72= Tff7b72null
Te6edf3tokenTb4b4b4.Te6edf3connection Tff7b72= Tff7b72null
Te6edf3connectionCleanupInProgress Tff7b72= Tff7b72true
Tff7b72val Te6edf3cleanupCompletion Tff7b72= Te6edf3CompletableDeferredTff7b72<Tffa657UnitTff7b72>Tb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3connectionCleanupCompletion Tff7b72= Tffa657it Tb4b4b4}
Te6edf3ClaimedConnectionTb4b4b4(Te6edf3tokenTb4b4b4, Te6edf3connectionTb4b4b4, Te6edf3cleanupCompletionTb4b4b4)
Tb4b4b4}
T8b949e/** Caller must hold [connectionAdmissionLock]. */
Tff7b72private Tff7b72fun Td2a8ffownsConnectionLockedTb4b4b4(Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4, Te6edf3connectionTb4b4b4: Te6edf3SerialConnectionTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3activeConnectionToken Tff7b72=Tff7b72=Tff7b72= Te6edf3connectionToken Tff7b72&Tff7b72&
Te6edf3connectionTokenTb4b4b4.Te6edf3connection Tff7b72=Tff7b72=Tff7b72= Te6edf3connection Tff7b72&Tff7b72&
Te6edf3connRefTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4) Tff7b72=Tff7b72=Tff7b72= Te6edf3connection
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffcloseConnectionAndAwaitConnectTb4b4b4(Te6edf3waitForStoppedTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3claimed Tff7b72= Te6edf3claimConnectionTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3claimed Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3awaitPendingConnectionCleanupTb4b4b4(Tb4b4b4)
Tff7b72return Tff7b72false
Tb4b4b4}
Tff7b72try Tb4b4b4{
Te6edf3closeClaimedConnectionTb4b4b4(Te6edf3claimedTb4b4b4, Te6edf3waitForStoppedTb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3finishConnectionCleanupTb4b4b4(Te6edf3claimedTb4b4b4.Te6edf3cleanupCompletionTb4b4b4)
Tb4b4b4}
Tff7b72return Tff7b72true
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffawaitPendingConnectionCleanupTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{ Te6edf3connectionCleanupCompletion Tb4b4b4}Tff7b72?.Te6edf3awaitTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffcloseClaimedConnectionTb4b4b4(Te6edf3claimedTb4b4b4: Te6edf3ClaimedConnectionTb4b4b4, Te6edf3waitForStoppedTb4b4b4: Tffa657BooleanTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3completed Tff7b72=
Te6edf3claimedTb4b4b4.Te6edf3tokenTb4b4b4.Te6edf3lifecycleTb4b4b4.Te6edf3close Tb4b4b4{
Te6edf3claimedTb4b4b4.Te6edf3connectionTb4b4b4.Te6edf3closeTb4b4b4(Te6edf3waitForStoppedTb4b4b4)
Te6edf3claimedTb4b4b4.Te6edf3tokenTb4b4b4.Te6edf3connectCompletionTb4b4b4.Te6edf3awaitForCloseTb4b4b4(Ta5d6ff"Ta5d6ffconnection attemptTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3completedTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial connection teardown did not complete within its lifecycle boundsTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffDeferredTff7b72<Tffa657UnitTff7b72>Tb4b4b4.Te6edf3awaitForCloseTb4b4b4(Te6edf3phaseTb4b4b4: Tffa657StringTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3timeout Tff7b72= Te6edf3TransportLifecycleGateTb4b4b4.Te6edf3OPERATION_DRAIN_TIMEOUT
Tff7b72val Te6edf3completed Tff7b72=
Te6edf3withTimeoutOrNullTb4b4b4(Te6edf3timeoutTb4b4b4) Tb4b4b4{
Te6edf3awaitTb4b4b4(Tb4b4b4)
Tff7b72true
Tb4b4b4} Tff7b72=Tff7b72= Tff7b72true
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3completedTb4b4b4) Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial close timed out after Tffd700$Te6edf3timeoutTa5d6ff while waiting for Tffd700$Te6edf3phaseTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffdisconnectConnectionTb4b4b4(
Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionToken?Tb4b4b4,
Te6edf3waitForStoppedTb4b4b4: Tffa657BooleanTb4b4b4,
Te6edf3isPermanentTb4b4b4: Tffa657BooleanTb4b4b4,
Te6edf3errorMessageTb4b4b4: Tffa657String? Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3reasonTb4b4b4: Te6edf3TransportDisconnectReason? Tff7b72= Tff7b72nullTb4b4b4,
Tb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3claimed Tff7b72= Te6edf3claimConnectionTb4b4b4(Te6edf3connectionTokenTb4b4b4) Tff7b72?: Tff7b72return Tff7b72false
Te6edf3launchConnectionCleanup Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3closeClaimedConnectionTb4b4b4(Te6edf3claimedTb4b4b4, Te6edf3waitForStoppedTb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3notifyDeviceDisconnectTb4b4b4(Te6edf3waitForStoppedTb4b4b4, Te6edf3isPermanentTb4b4b4, Te6edf3errorMessageTb4b4b4, Te6edf3reasonTb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3finishConnectionCleanupTb4b4b4(Te6edf3claimedTb4b4b4.Te6edf3cleanupCompletionTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72return Tff7b72true
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8fflaunchConnectionCleanupTb4b4b4(Te6edf3blockTb4b4b4: Te6edf3suspend Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4) Tb4b4b4{
Te6edf3cleanupScopeTb4b4b4.Te6edf3handledLaunchTb4b4b4(Te6edf3start Tff7b72= Te6edf3CoroutineStartTb4b4b4.Te6edf3UNDISPATCHEDTb4b4b4) Tb4b4b4{ Te6edf3withContextTb4b4b4(Te6edf3NonCancellableTb4b4b4) Tb4b4b4{ Te6edf3blockTb4b4b4(Tb4b4b4) Tb4b4b4} Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffnotifyDeviceDisconnectTb4b4b4(
Te6edf3waitForStoppedTb4b4b4: Tffa657BooleanTb4b4b4,
Te6edf3isPermanentTb4b4b4: Tffa657BooleanTb4b4b4,
Te6edf3errorMessageTb4b4b4: Tffa657String?Tb4b4b4,
Te6edf3reasonTb4b4b4: Te6edf3TransportDisconnectReason?Tb4b4b4,
Tb4b4b4) Tb4b4b4{
T8b949e// Explicit close owns the terminal service-layer notification. Admission at emission time linearizes this
T8b949e// callback with close even when physical cleanup was deferred behind an older operation.
Te6edf3lifecycleTb4b4b4.Te6edf3runIfOpen Tb4b4b4{ Tff7b72superTb4b4b4.Te6edf3onDeviceDisconnectTb4b4b4(Te6edf3waitForStoppedTb4b4b4, Te6edf3isPermanentTb4b4b4, Te6edf3errorMessageTb4b4b4, Te6edf3reasonTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffconnectTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72when Tb4b4b4{
Te6edf3lifecycleTb4b4b4.Te6edf3isClosed Tff7b72-Tff7b72> Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Ignoring start after serial transport closeTa5d6ff" Tb4b4b4}
Te6edf3deferConnectUntilCleanupTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657Unit
Te6edf3hasActiveConnectionTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Ignoring start while serial generation is activeTa5d6ff" Tb4b4b4}
Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72val Te6edf3devices Tff7b72= Te6edf3serialDevicesTb4b4b4.Te6edf3value
T8b949e// Keep legacy path-based selections usable when a single serial device can be resolved unambiguously.
T8b949e// Generation ownership still binds all callbacks to this transport instance after the device is chosen.
Tff7b72val Te6edf3device Tff7b72= Te6edf3resolveSerialDeviceTb4b4b4(Te6edf3devicesTb4b4b4, Te6edf3addressTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3device Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3e Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial device not found at selected addressTa5d6ff" Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3openConnectionTb4b4b4(Te6edf3deviceTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffhasActiveConnectionTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{ Te6edf3activeConnectionToken Tff7b72!Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3connRefTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4) Tff7b72!Tff7b72= Tff7b72null Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffdeferConnectUntilCleanupTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72var Te6edf3cleanupTb4b4b4: Te6edf3DeferredTff7b72<Tffa657UnitTff7b72>Tff7b72? Tff7b72= Tff7b72null
Tff7b72val Te6edf3deferred Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3connectionCleanupInProgressTb4b4b4) Tb4b4b4{
Tff7b72false
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3connectAfterCleanupScheduledTb4b4b4) Tb4b4b4{
Te6edf3connectAfterCleanupScheduled Tff7b72= Tff7b72true
Te6edf3cleanup Tff7b72= Te6edf3checkNotNullTb4b4b4(Te6edf3connectionCleanupCompletionTb4b4b4)
Tb4b4b4}
Tff7b72true
Tb4b4b4}
Tb4b4b4}
Te6edf3cleanupTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3completion Tff7b72-Tff7b72>
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3completionTb4b4b4.Te6edf3awaitTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{ Te6edf3connectAfterCleanupScheduled Tff7b72= Tff7b72false Tb4b4b4}
Tb4b4b4}
Te6edf3connectTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72return Te6edf3deferred
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffopenConnectionTb4b4b4(Te6edf3deviceTb4b4b4: Te6edf3UsbSerialDriverTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3startupLease Tff7b72= Te6edf3lifecycleTb4b4b4.Te6edf3tryAcquireTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3startupLease Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Ignoring serial open after transport closeTa5d6ff" Tb4b4b4}
Tff7b72return
Tb4b4b4}
Tff7b72try Tb4b4b4{
Te6edf3openAdmittedConnectionTb4b4b4(Te6edf3deviceTb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3startupLeaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffopenAdmittedConnectionTb4b4b4(Te6edf3deviceTb4b4b4: Te6edf3UsbSerialDriverTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3stats Tff7b72= Te6edf3ConnectionStatsTb4b4b4(Te6edf3connectStartedAt Tff7b72= Te6edf3nowMillisTb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Opening serial device: Tffd700$Te6edf3deviceTa5d6ff" Tb4b4b4}
Tff7b72val Te6edf3connectionToken Tff7b72= Te6edf3ConnectionTokenTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3connection Tff7b72= Te6edf3createSerialConnectionTb4b4b4(Te6edf3deviceTb4b4b4, Te6edf3createConnectionListenerTb4b4b4(Te6edf3deviceTb4b4b4, Te6edf3connectionTokenTb4b4b4, Te6edf3statsTb4b4b4)Tb4b4b4)
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3publishConnectionTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3connectionTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial generation is active or still tearing down; closing unused connectionTa5d6ff" Tb4b4b4}
Te6edf3connectionTb4b4b4.Te6edf3closeTb4b4b4(Te6edf3waitForStopped Tff7b72= Tff7b72falseTb4b4b4)
Tff7b72return
Tb4b4b4}
Tff7b72try Tb4b4b4{
Te6edf3connectionTb4b4b4.Te6edf3connectTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
Te6edf3disconnectConnectionTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3waitForStopped Tff7b72= Tff7b72falseTb4b4b4, Te6edf3isPermanent Tff7b72= Tff7b72falseTb4b4b4, Te6edf3errorMessage Tff7b72= Te6edf3eTb4b4b4.Te6edf3messageTb4b4b4)
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial connect failedTa5d6ff" Tb4b4b4}
Te6edf3disconnectConnectionTb4b4b4(
Te6edf3connectionToken Tff7b72= Te6edf3connectionTokenTb4b4b4,
Te6edf3waitForStopped Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3isPermanent Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3errorMessage Tff7b72= Te6edf3eTb4b4b4.Te6edf3messageTb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3connectionTokenTb4b4b4.Te6edf3connectCompletionTb4b4b4.Te6edf3completeTb4b4b4(Tffa657UnitTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffcreateConnectionListenerTb4b4b4(
Te6edf3deviceTb4b4b4: Te6edf3UsbSerialDriverTb4b4b4,
Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4,
Te6edf3statsTb4b4b4: Te6edf3ConnectionStatsTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3SerialConnectionListener Tff7b72= Tff7b72object Tb4b4b4: T56d364SerialConnectionListener Tb4b4b4{
Tff7b72override Tff7b72fun Td2a8ffonMissingPermissionTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(
Te6edf3disconnectConnectionTb4b4b4(
Te6edf3connectionToken Tff7b72= Te6edf3connectionTokenTb4b4b4,
Te6edf3waitForStopped Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3isPermanent Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3reason Tff7b72= Te6edf3TransportDisconnectReasonTb4b4b4.Te6edf3UsbPermissionDeniedTb4b4b4,
Tb4b4b4)
Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffSerial connection unavailable: USB permission deniedTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffonConnectedTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3handleConnectedTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3statsTb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffonDataReceivedTb4b4b4(Te6edf3bytesTb4b4b4: Te6edf3ByteArrayTb4b4b4) Tff7b72= Te6edf3handleDataReceivedTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3statsTb4b4b4, Te6edf3bytesTb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffonDisconnectedTb4b4b4(Te6edf3thrownTb4b4b4: Te6edf3Exception?Tb4b4b4) Tff7b72= Te6edf3handleDisconnectedTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3statsTb4b4b4, Te6edf3deviceTb4b4b4, Te6edf3thrownTb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffhandleConnectedTb4b4b4(Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4, Te6edf3statsTb4b4b4: Te6edf3ConnectionStatsTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3operation Tff7b72= Te6edf3admitConnectionOperationTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3requireReady Tff7b72= Tff7b72falseTb4b4b4) Tff7b72?: Tff7b72return
Tff7b72var Te6edf3wakeFailureTb4b4b4: Te6edf3Exception? Tff7b72= Tff7b72null
Tff7b72try Tb4b4b4{
Te6edf3statsTb4b4b4.Te6edf3connectedAt Tff7b72= Te6edf3nowMillis
Tff7b72val Te6edf3connectionTime Tff7b72= Te6edf3statsTb4b4b4.Te6edf3connectedAt Tff7b72- Te6edf3statsTb4b4b4.Te6edf3connectStartedAt
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial device connected in Tffd700${Te6edf3connectionTimeTffd700}Ta5d6ffmsTa5d6ff" Tb4b4b4}
Te6edf3wakeFailure Tff7b72= Te6edf3sendWakeBytesTb4b4b4(Te6edf3operationTb4b4b4.Te6edf3connectionTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3wakeFailure Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3readyToPublish Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{
Te6edf3ownsConnectionLockedTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3operationTb4b4b4.Te6edf3connectionTb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3owns Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3ownsTb4b4b4) Te6edf3connectionReadyTb4b4b4.Te6edf3setTb4b4b4(Tff7b72trueTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3readyToPublishTb4b4b4) Tb4b4b4{
Te6edf3lifecycleTb4b4b4.Te6edf3runIfOpen Tb4b4b4{
Tff7b72val Te6edf3stillOwned Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{
Te6edf3ownsConnectionLockedTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3operationTb4b4b4.Te6edf3connectionTb4b4b4) Tff7b72&Tff7b72& Te6edf3connectionReadyTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3stillOwnedTb4b4b4) Te6edf3callbackTb4b4b4.Te6edf3onConnectTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3operationTb4b4b4.Te6edf3leaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Tb4b4b4}
Te6edf3wakeFailureTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3handleWakeFailureTb4b4b4(Te6edf3connectionTokenTb4b4b4, Tffa657itTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffsendWakeBytesTb4b4b4(Te6edf3connectionTb4b4b4: Te6edf3SerialConnectionTb4b4b4)Tb4b4b4: Te6edf3Exception? Tff7b72= Tff7b72try Tb4b4b4{
T8b949e// SerialConnection.sendBytes is asynchronous. This lease guarantees handoff to this exact connection
T8b949e// generation's write queue; it does not claim physical wire delivery.
Te6edf3connectionTb4b4b4.Te6edf3sendBytesTb4b4b4(Te6edf3StreamFrameCodecTb4b4b4.Te6edf3WAKE_BYTESTb4b4b4)
Tff7b72null
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3e
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffhandleWakeFailureTb4b4b4(Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4, Te6edf3failureTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3failureTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial wake failed; ending connection generationTa5d6ff" Tb4b4b4}
Te6edf3disconnectConnectionTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3waitForStopped Tff7b72= Tff7b72falseTb4b4b4, Te6edf3isPermanent Tff7b72= Tff7b72falseTb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffhandleDataReceivedTb4b4b4(Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4, Te6edf3statsTb4b4b4: Te6edf3ConnectionStatsTb4b4b4, Te6edf3bytesTb4b4b4: Te6edf3ByteArrayTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3operation Tff7b72= Te6edf3admitConnectionOperationTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3requireReady Tff7b72= Tff7b72falseTb4b4b4) Tff7b72?: Tff7b72return
Tff7b72try Tb4b4b4{
Te6edf3statsTb4b4b4.Te6edf3packetsReceivedTff7b72+Tff7b72+
Te6edf3statsTb4b4b4.Te6edf3bytesReceived Tff7b72+Tff7b72= Te6edf3bytesTb4b4b4.Te6edf3size
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{
Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial received packet #Tffd700${Te6edf3statsTb4b4b4.Te6edf3packetsReceivedTffd700}Ta5d6ff - Ta5d6ff" Tff7b72+
Ta5d6ff"Tffd700${Te6edf3bytesTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff byte(s) (Total RX: Tffd700${Te6edf3statsTb4b4b4.Te6edf3bytesReceivedTffd700}Ta5d6ff bytes)Ta5d6ff"
Tb4b4b4}
Te6edf3bytesTb4b4b4.Te6edf3forEachTb4b4b4(Tff7b72::Te6edf3readCharTb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3operationTb4b4b4.Te6edf3leaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffhandleDisconnectedTb4b4b4(
Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4,
Te6edf3statsTb4b4b4: Te6edf3ConnectionStatsTb4b4b4,
Te6edf3deviceTb4b4b4: Te6edf3UsbSerialDriverTb4b4b4,
Te6edf3thrownTb4b4b4: Te6edf3Exception?Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3lifecycleTb4b4b4.Te6edf3isClosedTb4b4b4) Tff7b72return
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3disconnectConnectionTb4b4b4(Te6edf3connectionTokenTb4b4b4, Te6edf3waitForStopped Tff7b72= Tff7b72falseTb4b4b4, Te6edf3isPermanent Tff7b72= Tff7b72falseTb4b4b4)Tb4b4b4) Tff7b72return
Tff7b72val Te6edf3uptime Tff7b72= Tff7b72if Tb4b4b4(Te6edf3statsTb4b4b4.Te6edf3connectedAt Tff7b72> T79c0ff0Tb4b4b4) Te6edf3nowMillis Tff7b72- Te6edf3statsTb4b4b4.Te6edf3connectedAt Tff7b72else T79c0ff0
Te6edf3thrownTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3error Tff7b72-Tff7b72> Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3errorTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial error after Tffd700${Te6edf3uptimeTffd700}Ta5d6ffms: Tffd700${Te6edf3errorTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4} Tb4b4b4}
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{
Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial device disconnected - Device: Tffd700$Te6edf3deviceTa5d6ff, Uptime: Tffd700${Te6edf3uptimeTffd700}Ta5d6ffms, Ta5d6ff" Tff7b72+
Ta5d6ff"Ta5d6ffPackets RX: Tffd700${Te6edf3statsTb4b4b4.Te6edf3packetsReceivedTffd700}Ta5d6ff (Tffd700${Te6edf3statsTb4b4b4.Te6edf3bytesReceivedTffd700}Ta5d6ff bytes)Ta5d6ff"
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffpublishConnectionTb4b4b4(Te6edf3connectionTokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4, Te6edf3connectionTb4b4b4: Te6edf3SerialConnectionTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3generationAvailable Tff7b72=
Tff7b72!Te6edf3lifecycleTb4b4b4.Te6edf3isClosed Tff7b72&Tff7b72&
Tff7b72!Te6edf3connectionCleanupInProgress Tff7b72&Tff7b72&
Te6edf3activeConnectionToken Tff7b72=Tff7b72= Tff7b72null Tff7b72&Tff7b72&
Te6edf3connRefTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4) Tff7b72=Tff7b72= Tff7b72null
Tff7b72if Tb4b4b4(Te6edf3generationAvailableTb4b4b4) Tb4b4b4{
Te6edf3connectionTokenTb4b4b4.Te6edf3connection Tff7b72= Te6edf3connection
Te6edf3connRefTb4b4b4.Te6edf3setTb4b4b4(Te6edf3connectionTb4b4b4)
Te6edf3activeConnectionToken Tff7b72= Te6edf3connectionToken
Te6edf3connectionReadyTb4b4b4.Te6edf3setTb4b4b4(Tff7b72falseTb4b4b4)
Tb4b4b4}
Te6edf3generationAvailable
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8fffinishConnectionCleanupTb4b4b4(Te6edf3completionTb4b4b4: Te6edf3CompletableDeferredTff7b72<Tffa657UnitTff7b72>Tb4b4b4) Tb4b4b4{
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3connectionCleanupCompletion Tff7b72=Tff7b72=Tff7b72= Te6edf3completionTb4b4b4) Tb4b4b4{
Te6edf3connectionCleanupCompletion Tff7b72= Tff7b72null
Te6edf3connectionCleanupInProgress Tff7b72= Tff7b72false
Tb4b4b4}
Tb4b4b4}
Te6edf3completionTb4b4b4.Te6edf3completeTb4b4b4(Tffa657UnitTb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffhandleSendToRadioTb4b4b4(Te6edf3pTb4b4b4: Te6edf3ByteArrayTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3transportLease Tff7b72= Te6edf3lifecycleTb4b4b4.Te6edf3tryAcquireTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3operation Tff7b72=
Te6edf3transportLeaseTff7b72?.Te6edf3let Tb4b4b4{
Tff7b72val Te6edf3token Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{ Te6edf3activeConnectionToken Tb4b4b4}
Te6edf3tokenTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3active Tff7b72-Tff7b72> Te6edf3admitConnectionOperationTb4b4b4(Te6edf3activeTb4b4b4, Te6edf3requireReady Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72return Tff7b72if Tb4b4b4(Te6edf3transportLease Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3operation Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3transportLeaseTff7b72?.Te6edf3releaseTb4b4b4(Tb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial connection not available, cannot send Tffd700${Te6edf3pTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff bytesTa5d6ff" Tb4b4b4}
Tff7b72false
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3queueFramedSendTb4b4b4(
Te6edf3payload Tff7b72= Te6edf3pTb4b4b4,
Te6edf3writer Tff7b72= Tb4b4b4{ Te6edf3bytes Tff7b72-Tff7b72> Te6edf3operationTb4b4b4.Te6edf3connectionTb4b4b4.Te6edf3sendBytesTb4b4b4(Te6edf3bytesTb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3onCompletion Tff7b72= Tb4b4b4{
Te6edf3operationTb4b4b4.Te6edf3leaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Te6edf3transportLeaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffadmitConnectionOperationTb4b4b4(Te6edf3tokenTb4b4b4: Te6edf3ConnectionTokenTb4b4b4, Te6edf3requireReadyTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Te6edf3ConnectionOperation? Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3connection Tff7b72= Te6edf3connRefTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3ready Tff7b72= Tff7b72!Te6edf3requireReady Tff7b72|Tff7b72| Te6edf3connectionReadyTb4b4b4.Te6edf3getTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3connection Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Tff7b72!Te6edf3ownsConnectionLockedTb4b4b4(Te6edf3tokenTb4b4b4, Te6edf3connectionTb4b4b4) Tff7b72|Tff7b72| Tff7b72!Te6edf3readyTb4b4b4) Tb4b4b4{
Tff7b72null
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3tokenTb4b4b4.Te6edf3lifecycleTb4b4b4.Te6edf3tryAcquireTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3lease Tff7b72-Tff7b72> Te6edf3ConnectionOperationTb4b4b4(Te6edf3tokenTb4b4b4, Te6edf3connectionTb4b4b4, Te6edf3leaseTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffkeepAliveTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3heartbeatSenderTb4b4b4.Te6edf3sendHeartbeatTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffsendBytesTb4b4b4(Te6edf3pTb4b4b4: Te6edf3ByteArrayTb4b4b4) Tb4b4b4{
T8b949e// Raw stream writes are part of the pre-handshake wake/framing path, so they may run before the connection
T8b949e// generation reports ready. Normal packet sends through handleSendToRadio require a ready generation.
Tff7b72val Te6edf3transportLease Tff7b72= Te6edf3lifecycleTb4b4b4.Te6edf3tryAcquireTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3token Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3connectionAdmissionLockTb4b4b4) Tb4b4b4{ Te6edf3activeConnectionToken Tb4b4b4}
Tff7b72val Te6edf3operation Tff7b72=
Te6edf3transportLeaseTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3tokenTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3active Tff7b72-Tff7b72> Te6edf3admitConnectionOperationTb4b4b4(Te6edf3activeTb4b4b4, Te6edf3requireReady Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4} Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3transportLease Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3operation Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3transportLeaseTff7b72?.Te6edf3releaseTb4b4b4(Tb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial connection not available, cannot send Tffd700${Te6edf3pTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff bytesTa5d6ff" Tb4b4b4}
Tff7b72return
Tb4b4b4}
Tff7b72try Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3addressTa5d6ff] Serial queueing Tffd700${Te6edf3pTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff bytesTa5d6ff" Tb4b4b4}
Te6edf3operationTb4b4b4.Te6edf3connectionTb4b4b4.Te6edf3sendBytesTb4b4b4(Te6edf3pTb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3operationTb4b4b4.Te6edf3leaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Te6edf3transportLeaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.12s